﻿using System;
using System.Collections;
using System.Text;
using Special = System.Collections.Specialized;
using Generics = System.Collections.Generic;
using System.Collections.Generic;

namespace Xylee.Common
{
    /// <summary>
    /// XApp refers to the Xyliea application framework 
    /// that houses navigation, commands, persistance, and context 
    /// management throughout the usage of the program. In order to 
    /// correctly monitor usage of the framework this class will 
    /// only allow certain types to be implemented for usage.
    /// </summary>
    public class XApp
    {
        public static XApp Current = new XApp();
        private XApp()
        {
            // Create command manager, persistence handlers, navigation.. etc
            commands = new CommandManager();
            navigation = new Navigation();
            portals = new List<IPortal>();
            modules = new List<Xylee.Common.Modules.Module>();
            loader = new Xylee.Common.Modules.BootStrapLoader();
            if (LoadStart != null)
                LoadStart(this, new EventArgs());
            if (LoadComplete != null)
                LoadComplete(this, new EventArgs());
        }

        private CommandManager commands;
        private Navigation navigation;
        private List<IPortal> portals;
        private List<Modules.Module> modules;
        private Modules.BootStrapLoader loader;
        private object mainWindow;

        public CommandManager Commands
        {
            get { return this.commands; }
        }

        public Navigation Navigate
        {
            get { return this.navigation; }
        }

        public List<IPortal> AvailablePortals
        {
            get { return this.portals; }
            set { this.portals = value; }
        }

        public List<Modules.Module> AvailableModules
        {
            get { return this.modules; }
        }

        public Modules.BootStrapLoader ModuleLoader
        {
            get { return this.loader; }
        }

        public event EventHandler LoadStart;
        public event EventHandler LoadComplete;
        public event EventHandler ModuleLoaded;
        public event EventHandler ModuleUnloaded;
        public event EventHandler ModuleDownloaded;
        public event EventHandler Shutdown;
        public event EventHandler UpdateContext;
        public event EventHandler SaveState;

        internal sealed class ModuleSettings
        {
            private IDictionary settings;

            public ModuleSettings()
            {
                this.settings = new Special.HybridDictionary();
            }

            
        }

        /// <summary>
        /// Protected command management class for executing and 
        /// undoing commands, as well as registering and removing 
        /// them from the application command scope.
        /// </summary>
        public class CommandManager
        {
            private IDictionary definitions;
            private Generics.Queue<ICommand> commandList;

            public CommandManager()
            {
                this.definitions = new Special.HybridDictionary();
                this.commandList = new Generics.Queue<ICommand>();
            }

            /// <summary>
            /// Adds a command to the protected domain.
            /// </summary>
            /// <typeparam name="Command">The type associated with any 
            ///     <seealso cref="ICommand"/> concrete implementation.</typeparam>
            /// <typeparam name="Factory">The type associated with any 
            ///     <seealso cref="ICommandFactory"/> concrete implementation.</typeparam>
            /// <returns>True if the command can be added, false otherwise.</returns>
            public bool AddCommand<Command, Factory>()
                where Command : ICommand
                where Factory : ICommandFactory
            {
                if (this.definitions.Contains(typeof(Command)))
                    return false;

                this.definitions.Add(typeof(Command), typeof(Factory));
                return true;
            }

            /// <summary>
            /// Removes a command from the protected domain.
            /// </summary>
            /// <typeparam name="Command">The type associated with any 
            ///     <seealso cref="ICommand"/> concrete implementation.</typeparam>
            /// <returns>True if the command can be removed, false otherwise.</returns>
            public bool RemoveCommand<Command>()
                where Command : ICommand
            {
                if (!this.definitions.Contains(typeof(Command)))
                    return false;

                this.definitions.Remove(typeof(Command));
                return true;
            }

            /// <summary>
            /// Executes an internal command within the current app domain.
            /// This calls the Command's ExecuteWithViewable method with the specified 
            /// viewing object content.
            /// </summary>
            /// <typeparam name="Command">The type associated with any 
            ///     <seealso cref="ICommand"/> concrete implementation.</typeparam>
            /// <param name="value">The <seealso cref="IViewable"/> that attributes to the success or usage 
            /// of executing a command, these are simply know for being command parameters.</param>
            public void ExecuteWithViewable<Command>(IViewable value)
                where Command : ICommand, new()
            {
                ICommandFactory cmdFactory = Manufacture.CreateFactory((Type)(this.definitions[typeof(Command)]));
                ICommand cmd = cmdFactory.CreateCommandWithViewable(value);
                cmd.Execute();
            }

            /// <summary>
            /// Executes an internal command within the current app domain.
            /// This calls the Command's Execute method.
            /// </summary>
            /// <typeparam name="Command">The type associated with any 
            ///     <seealso cref="ICommand"/> concrete implementation.</typeparam>
            public void Execute<Command>()
                where Command : ICommand, new()
            {
                ICommandFactory cmdFactory = Manufacture.CreateFactory((Type)(this.definitions[typeof(Command)]));
                Command cmd = cmdFactory.CreateCommand<Command>();
                cmd.Execute();
            }

            /// <summary>
            /// Puts the specified command in a list of 
            /// commands to which may be executed at a later time.
            /// </summary>
            /// <param name="item"><seealso cref="ICommand"/> instance to execute.</param>
            public void EnQueueCommand(ICommand item)
            {
                this.commandList.Enqueue(item);
            }

            /// <summary>
            /// Returns the first <seealso cref="ICommand"/> item 
            /// in the queue list in order to be executed or used.
            /// </summary>
            /// <returns><seealso cref="ICommand"/></returns>
            public ICommand DeQueueCommand()
            {
                return this.commandList.Dequeue();
            }

            /// <summary>
            /// Executes the queued <seealso cref="ICommand"/> instances.
            /// </summary>
            public void ExecuteQueueList()
            {
                while (commandList.Count > 0)
                {
                    ICommand cmd = commandList.Dequeue();
                    cmd.Execute();
                }
            }
        }
    }
}
